package com.pad.producter.utils;

public class SnowflakeIdWorker {  
    
    private final long twepoch = 1288834974657L; // 起始时间戳，可以自定义  
    private long workerId; // 工作机器ID  
    private long datacenterId; // 数据中心ID  
    private long sequence = 0L; // 毫秒内序列  
  
    private final long workerIdBits = 5L; // 机器ID所占的位数  
    private final long datacenterIdBits = 5L; // 数据中心ID所占的位数  
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // 支持的最大机器ID数量  
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 支持的最大数据中心ID数量  
    private final long sequenceBits = 12L; // 毫秒内序列所占的位数  
  
    private final long workerIdShift = sequenceBits; // 机器ID左移位数  
    private final long datacenterIdShift = sequenceBits + workerIdBits; // 数据中心ID左移位数  
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; // 时间截左移位数  
    private final long sequenceMask = -1L ^ (-1L << sequenceBits); // 毫秒内序列的掩码  
  
    private long lastTimestamp = -1L; // 上次生成ID的时间截  
  
    public SnowflakeIdWorker(long workerId, long datacenterId) {  
        if (workerId > maxWorkerId || workerId < 0) {  
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));  
        }  
        if (datacenterId > maxDatacenterId || datacenterId < 0) {  
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));  
        }  
        this.workerId = workerId;  
        this.datacenterId = datacenterId;  
    }  
  
    public synchronized long nextId() {  
        long timestamp = timeGen();  
  
        if (timestamp < lastTimestamp) {  
            throw new RuntimeException(String.format("clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));  
        }  
  
        if (lastTimestamp == timestamp) {  
            sequence = (sequence + 1) & sequenceMask;  
            if (sequence == 0) {  
                timestamp = tilNextMillis(lastTimestamp);  
            }  
        } else {  
            sequence = 0L;  
        }  
  
        lastTimestamp = timestamp;  
  
        return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;  
    }  
  
    protected long tilNextMillis(long lastTimestamp) {  
        long timestamp = timeGen();  
        while (timestamp <= lastTimestamp) {  
            timestamp = timeGen();  
        }  
        return timestamp;  
    }  
  
    protected long timeGen() {  
        return System.currentTimeMillis();  
    }  
  
    public static void main(String[] args) {  
        SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1);  
        for (int i = 0; i < 1000; i++) {  
            long id = idWorker.nextId();  
            System.out.println(Long.toBinaryString(id));  
            System.out.println(id);  
        }  
    }  
}